Package-level declarations
Types
Thrown from AbortSignal.throwIfAborted when the signal has fired.
Cancellation primitive matching the Vercel AI SDK v6 AbortSignal shape.
The agent contract — what application code depends on (best practice #7). ToolLoopAgent is the default implementation, but other implementations exist (e.g. a DurableAgent that journals to disk for offline-resilient mode, a SubagentTestAgent that records calls for unit tests).
Per-call lifecycle hooks. These mirror the ones on the agent constructor but apply to a single Agent.generate / Agent.stream invocation — useful for request-scoped logging, tracing, or progress UI.
Tool-loop error taxonomy (Phase 4C gap #25). The agent loop's failure modes were previously all String messages on StreamEvent.Error / StreamEvent.ToolError; catch sites had no way to discriminate "model called an unknown tool" from "executor threw" from "input decode failed" without parsing the message.
Returned from prepareCall. Any non-null field overrides the agent default for this invocation only.
Provider warning for a call that still completed. Mirrors v6's CallWarning shape without baking provider-specific warning enums into common code.
Content part of a ModelMessage. Sealed so consumers exhaust over variants — adding a new content type forces a compile error at every dispatch site.
The base64 bytes + media type of a downloaded asset.
Downloads a remote asset for convertToLanguageModelPrompt.
Marks a declaration as experimental: a surface whose shape may change or be removed in any release without going through the normal deprecation cycle.
Why a generation step ended.
Final output of Agent.generate. When pendingApprovals is non-empty, the loop paused on tool approval — call Agent.generate again with messages plus tool-approval-response messages to resume.
Token usage reported by an image model, when available. Mirrors v6's ImageModelUsage.
Marks a declaration as internal to the AI SDK implementation: visible across module boundaries for technical reasons (KMP source sets, inlining), but not part of the supported public contract. It may change or be removed at any time.
Provider-neutral model surface. Per invariant I-4 / I-9, application code never depends on a specific provider — it depends on this interface, and provider-specific differences live in middleware (see LanguageModelMiddleware).
Single parameter envelope for both generate and stream so middleware can wrap both the same way and wrapLanguageModel only needs one pass-through shape.
Provider middleware. Per invariants I-9 and R-11, provider differences (Anthropic-specific options, OpenAI-specific options, on-device-only sampling knobs) live in middleware — NEVER in agent or orchestration code. If you find yourself branching on model.modelId.startsWith("...") inside an agent, that's a missing middleware.
Request metadata recorded by HTTP-backed or gateway providers.
Response metadata recorded by HTTP-backed or gateway providers.
One-shot generate result.
Provider stream plus request/response metadata known before collection.
Tool advertisement at the model surface — the JSON-schema shape the provider needs. Distinct from the application-side Tool which carries a Kotlin executor; this is the wire shape that crosses into a provider.
Port-side log sink for non-fatal warnings and informational events. Mirrors v6's logger/log-warnings.ts (per historical parity gap #31) — the agent loop, middleware, and tool dispatch surface warnings here so consumers can route them to Logcat / Crashlytics / their own telemetry without the port hard-coding a logging dependency.
Transport interface for MCP communication. Implementations may wrap stdio, Streamable HTTP, SSE, WebSockets, or a test fixture.
What a middleware receives. Contains:
Which operation a LanguageModelMiddleware.transformParams call is transforming.
v6 wire-shape message — the type passed to LanguageModel generations. Renamed from CoreMessage (v5) per the AI SDK v6 migration.
Thrown when no object could be generated (the model failed, or its output could not be parsed/validated). Carries the diagnostic context upstream's NoObjectGeneratedError exposes so callers can inspect the raw text, the response metadata, the token usage, and the finish reason of the failed call.
Drop-everything logger. Default when no DI-injected impl is wired.
No-op ToolStreamWriter — the default on a ToolExecutionContext constructed outside the loop (test fixtures, the approval-resume path before the loop wires a real writer). Drops every write.
Fired when generation is aborted via AbortSignal before it finishes. Carries the steps completed up to the abort. Mirrors upstream's onAbort({ steps }).
Each individual stream chunk, alongside the step it belongs to.
Lifecycle hook event types (best practice #10). Hooks are observation points — they do NOT modify behavior. If a hook needs to influence the loop, the right place is PrepareStepScope / PrepareCallScope.
Fired before each loop step's model call. Per historical parity gap #35, the payload was extended from (stepNumber, messages) to carry the full prepared request (post prepareCall + prepareStep overrides) plus accumulated priorSteps so observers can:
Fired immediately after a tool's executor returns or throws. Exactly one of outputJson or errorMessage is non-null.
Fired immediately before a tool's executor runs. Carries the parsed tool call envelope and the messages-list snapshot so observers can record context (e.g. for tracing).
Structured output for generateText / streamText / Agent.
Result of parsePartialJson: value is non-null only on the two success states.
Outcome of parsePartialJson, mirroring v6's four state strings.
A pending tool-call approval surfaced from Agent.generate / Agent.stream. Per v6 RPC semantics, generation completes when one or more tools require approval — the host inspects GenerateResult.pendingApprovals, presents UI, and resumes by calling Agent.generate again with messages = result.messages + toolApprovalResponseMessage(...).
Scope for prepareCall, run once before the loop starts. Useful for RAG context injection, per-user customization, database lookups that shouldn't repeat per step.
Scope for prepareStep, run before every step in the loop. Used for: model routing per step (cheap model for step 1 + 2, expensive for step 3), tool gating per step (only the search tool is callable on step 1), dynamic system prompts, message compression.
Wire-level constraint on what shape the model is allowed to emit. Mirrors v6's responseFormat (per call-settings.ts:103-128 → historical parity gap #20). Distinct from Output — Output is the post-decode wrapper that turns text into typed values; ResponseFormat is what the provider sees at call time.
Snapshot of one completed loop step — surfaced to OnStepFinishEvent and accumulated in the loop state for PrepareStepScope.steps.
Returned from prepareStep. Any non-null field overrides the agent default / prepareCall value for this step only.
First-class loop stop conditions (invariant I-7). The SDK manages the loop; consumers express completion as a StopCondition passed to the agent constructor or generateText.
Sealed event stream emitted by LanguageModel.stream and surfaced to application code via Agent.stream. Mirrors the v6 stream-part taxonomy (per packages/ai/src/generate-text/stream-text-result.ts in vercel/ai) adapted to Kotlin sealed classes for exhaustive when.
A Tool whose executor is a Flow — it can emit preliminary snapshots before the final value. The LAST emission is what feeds the model on subsequent turns; earlier emissions surface as StreamEvent.ToolResult(preliminary = true) for UI consumption only. Extend this (instead of Tool) when a tool can produce a useful early snapshot — a small summary, count, or status — before the full result is ready.
The final object plus terminal metadata of a StreamObjectResult.finish.
A typed streaming-object result — the v6 StreamObjectResult surface. Wraps the underlying StreamEvent flow so callers get the object as it builds and the final typed value, without hand-parsing the stream.
The v7 telemetry integration seam (upstream's Telemetry, the revamped TelemetryIntegration): implement it ONCE and the loop feeds it every lifecycle event of every invocation — agent start/finish, step start/finish, model-call start/finish, tool-call start/finish (including tool executions resumed after an approval pause), errors, and aborts. Upstream: "Instead of wiring up individual callbacks on every call, you implement a Telemetry once and register it globally or pass it via telemetry.integrations."
Correlation envelope for one agent invocation (one generate/stream call). Every Telemetry event of that invocation carries the same callId, so an integration can reconstruct per-call traces even when a single agent instance serves concurrent calls. agentId/agentVersion mirror Agent.id/Agent.version (parity gap #33: "useful for telemetry"); functionId comes from TelemetrySettings.functionId.
Fired before one step's model call — carries the EXACT prepared params sent to the provider.
Fired after one step's model call streamed to completion.
Ordered registry of Telemetry integrations, keyed by Telemetry.name (re-register replaces, keeping the original position).
Telemetry settings for an agent or call (upstream v7 telemetry, the stabilized experimental_telemetry). With the v7 revamp, telemetry is opt-out: once an integration is registered via registerTelemetry, every agent invocation emits events to it automatically.
A tool the LLM can call. There are two idiomatic ways to define one:
Callback invoked when a tool call's JSON arguments fail to decode (the model emitted JSON that doesn't match the tool's input schema, or referenced an unknown tool). Return a corrected ContentPart.ToolCall to retry execution, or null to give up (the loop emits StreamEvent.ToolError for this call).
Whether the LLM should call a tool, no tool, a specific tool, etc.
What Tool.execute sees as this. Holds the typed application context (whatever the agent's callOptionsSchema says) plus the abort signal (invariant I-10: subagent tool handlers MUST forward this), the current step number, and the running message list.
Abstract base Agent implementation — the canonical v6 ToolLoopAgent. Extend it; do not instantiate it. A concrete agent subclasses this (e.g. class MyAgent(...) : ToolLoopAgent<C, O>(...)) so the agent's identity, tools, lifecycle overrides, and DI live in one named type — never a bare ToolLoopAgent(...) held as a field.
Actions the host dispatches to drive the agent. Mirrors the Action sealed type a Compose ViewModel exposes — the agent is the "model" of an MVI loop.
Engine-shape state for ToolLoopAgent.
Options bag passed to predicate callbacks (Tool.needsApproval, Tool.toModelOutput). Mirrors v6's {toolCallId, messages, experimental_context} argument shape (per historical parity gap #17). Lets a predicate decide based on the conversation history or the current call's identity, not just the input.
Structured return type for Tool.toModelOutput. Replaces the flat String return per historical parity gap #14. Lets a tool supply EITHER a short plain-text summary OR a structured JSON payload OR a typed error to the model — the agent's loop bridges each into the wire-format ContentPart.ToolResult.modelVisible appropriately:
Lets a tool's executor write custom events into the agent's active output stream — the port's equivalent of v6's UIMessageStreamWriter (per historical parity gap #21). Distinct from the streamingTool mechanism (which surfaces progress as ToolResult(preliminary = true)): the writer pushes ARBITRARY StreamEvents — e.g. a transient status line (StreamEvent.TextDelta) or a custom data payload (StreamEvent.Raw via writeData) — that don't have to be tool-result-shaped. Writes interleave with the tool's own emissions in stream order. streamToUiMessages ignores Raw by default, so a consumer that wants custom data intercepts the Flow<StreamEvent> before UI conversion.
Token-usage tracking, surfaced on completed steps and final results. Per historical parity gap #19, the shape mirrors v6's rich tree — input tokens split into noCache / cacheRead / cacheWrite and output tokens split into text / reasoning plus a raw slot for provider-specific payloads.
Properties
A signal that is never aborted. Useful as a default.
Global registry — upstream v7 registerTelemetry: register once at startup, all calls emit.
Functions
Bind an abort signal to a Job so the signal fires when the job completes (cancelled or otherwise). Lets a parent scope's lifetime automatically cancel anything observing the signal.
Stop only when all conditions report done.
Stop when any of conditions reports done. v6's array-of-conditions shape.
Decode the inline base64 payload to bytes.
Like bytes but returns null for a URL-backed file instead of throwing.
Resolve a prompt for a specific model — the port of upstream's convertToLanguageModelPrompt:
Runtime-typed tool equivalent to v6's dynamicTool. Inputs and outputs are raw JsonElement values, so the tool can be registered from external manifests or MCP-style runtime catalogs.
The effective approval ID — explicit PendingApproval.approvalId or fallback to PendingApproval.toolCallId.
Complete a partial/truncated JSON string so Json.parseToJsonElement can read it. Returns "" when nothing valid was scanned (e.g. a lone -). See parsePartialJson for the parse wrapper.
Deprecated v6 compatibility helper. Prefer generateText with output = ...; this wrapper exists for call sites that still use the object-generation vocabulary.
One-shot generation — invariant I-3, the only text entry point in v6.
Stop the moment the named tool is called in any step.
Build the JSON instruction block.
Splice injectJsonInstruction into a message list's system prompt.
Consolidated check: would the loop terminate after this state?
Stock self-healing repair: re-prompt the model with the tool's JSON schema + the failed args + the parse error, asking for corrected JSON. If the second response parses cleanly, return a ContentPart.ToolCall with the corrected input; otherwise return null (the agent loop surfaces StreamEvent.ToolError).
Parse possibly-partial JSON. Mirrors Vercel AI SDK v6 parsePartialJson:
Stop when the model has emitted the same (toolName, input) tuple n consecutive steps in a row — i.e. the loop is spinning on a tool whose result didn't change the model's behavior. Documented anti-pattern for small / on-device models that can't reason their way out of an unhelpful tool result; surfaced as a hard stop so the host renders the trapped state instead of looping until the step cap.
Retry block with exponential backoff, honoring server Retry-After headers, and surfacing the full attempt history as a RetryError on exhaustion — the contract upstream's retryWithExponentialBackoff exposes.
Sign one approval request. approvalId is the EFFECTIVE id (explicit approvalId ?: toolCallId).
Replay a recorded list of StreamEvents as a fresh cold Flow with configurable inter-chunk delay. Foundation for the caching middleware pattern: cache stream parts as List<StreamEvent>, on cache hit replay via simulateReadableStream so the stream contract is preserved.
Stop after n completed steps. v6's default is 20 if stopWhen omitted.
Top-level factory for Tool with a Flow-returning executor. Each emission lands as a StreamEvent.ToolResult; the LAST emission is the final tool result that feeds the model on subsequent turns, and all earlier emissions are surfaced as ToolResult(preliminary = true) for UI consumption only.
Deprecated v6 compatibility helper. Prefer streamText with output = ...; the KMP core streams typed StreamEvent values instead of returning a browser/Node stream facade.
Stream a structured object, returning a typed StreamObjectResult — the v6 streamObject surface (the older streamObject returns a raw event flow and is deprecated). Use StreamObjectResult.partialObjectStream for incremental UI or StreamObjectResult.objectValue for the final value.
Streaming generation — invariant I-3. Returns a cold Flow that drives one upstream call when collected. For tool-loop agents, use Agent.stream instead.
Top-level factory for Tool with a single-value executor. Mirrors v6's tool({...}) ergonomics in an idiomatic common Kotlin shape.
Compose middlewares over model into a new LanguageModel. Order: the first middleware in the list is the outermost wrapper — wrapGenerate runs first on the way in, last on the way out (innermost in the call stack, like Express middleware).